
use std::{ 
    fs, 
    error::Error,
    env, 
    sync::{mpsc, Arc, Mutex},
    thread
};

pub struct Config {
    pub query:String,
    pub file_path:String,
    pub ignore_case:bool,
}

impl  Config {
    pub fn buid(mut args:impl Iterator<Item = String>) ->Result<Config,&'static str>{
        args.next();

        let query = match args.next() {
            Some(arg)=>arg,
            None => return  Err("没有查询参数")
        };
        let file_path = match args.next() {
            Some(arg)=>arg,
            None=>return Err("没有查询文件")
        };
        // let query = args[1].clone();
        // let file_path = args[2].clone();
        let ignore_case = env::var("IGNORE_CASE").is_ok();
        Ok(Config{ query,file_path,ignore_case })
    }
}

// dynamic
pub fn run(config:Config) -> Result<(),Box<dyn Error>>{
    let contents = fs::read_to_string(config.file_path)?;

    // println!("With txt :\n{contents}");
    let results = if config.ignore_case {
        search_case_insensitive(&config.query, &contents)
    } else {
        search(&config.query,&contents)
    };
    for line in results{
        println!("{line}")
    }
    Ok(())
}

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    // let mut results = Vec::new();
    // for line in contents.lines() {
    //     if line.contains(query){
    //         results.push(line);
    //     }
    // }
    // results
    contents
    .lines()
    .filter(|line|line.contains(query))
    .collect()
}

pub fn search_case_insensitive<'a>(
    query: &str,
    contents: &'a str
) -> Vec<&'a str>{
    let query = query.to_lowercase();
    let mut results = Vec::new();
    for line in contents.lines() {
        if line.to_lowercase().contains(&query){
            results.push(line);
        }
    }
    results
}

// hello_server

pub struct ThreadPool{
    workers:Vec<Worker>,
    sender:Option<mpsc::Sender<Job>>,
}
type Job = Box<dyn FnOnce() + 'static + Send>;


impl ThreadPool {
    pub fn new(size: usize) -> ThreadPool {
        let (sender,receiver) = mpsc::channel();
        let receier = Arc::new(Mutex::new(receiver));
        let mut workers = Vec::with_capacity(size);

        for id in 0..size {
            workers.push(Worker::new(id,Arc::clone(&receier)));
        }
        ThreadPool { workers, sender:Some(sender) }
    }
    pub fn execute<F>(&self,f:F)
    where
        F:FnOnce()+Send+'static
    {
        let job = Box::new(f);
        self.sender.as_ref().unwrap().send(job).unwrap();
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self){
        drop(self.sender.take());
        for worker in &mut self.workers {
            println!("正在关闭 worker {}",worker.id);
            if let Some(thread) = worker.thread.take() {
                thread.join().unwrap();
            }
        }
    }
}

struct Worker {
    id:usize,
    thread: Option<thread::JoinHandle<()>>,
}

impl Worker {
    fn new(id:usize,reciver:Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker{
        let thread = thread::spawn(move|| loop{
            let msg = reciver.lock().unwrap().recv();
            match msg {
                Ok(job) =>{
                    println!("Worker {id} 得到一个 job");
                    job();
                },
                Err(_)=>{
                    println!("Worker {id} disconnected;正在关闭");
                    break;
                }
            }
        });
        Worker { id, thread:Some(thread) }
    }
}




#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn case_sensitive(){
        let query = "duct";
        let contents = "\
Rust:
safe, fast, productive.
Pick three.
Duct tape.";

        assert_eq!(vec!["safe, fast, productive."],search(query, contents));
    }

    #[test]
    fn case_insensitive(){
        let query = "rUsT";
        let contents = "\
Rust:
safe, fast, productive.
Pick three.
Trust me.";
        assert_eq!(
            vec!["Rust:", "Trust me."],
            search_case_insensitive(query, contents)
        );
    }
}